package org.hcyspartnoc.luoxin.utils.netty_chat;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import org.hcyspartnoc.luoxin.common.core.AjaxResult;
import org.hcyspartnoc.luoxin.common.enums.chat.ChatMessageTypeEnum;
import org.hcyspartnoc.luoxin.common.exception.BaseException;
import org.hcyspartnoc.luoxin.common.exception.chat.ChatException;
import org.hcyspartnoc.luoxin.pojo.dto.chat.ChatMessageDto;
import org.hcyspartnoc.luoxin.pojo.vo.chat.ChatCommonVo;
import org.hcyspartnoc.luoxin.utils.ChannelContextUtils;
import org.hcyspartnoc.luoxin.utils.LuoxinUtils;
import org.hcyspartnoc.luoxin.utils.redis.RedisComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ChannelHandler.Sharable
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    private static final Logger logger = LoggerFactory.getLogger(WebSocketHandler.class);
    private static final ConcurrentHashMap<Channel, Thread> V_COUNSELOR_ASK_CHANNEL_THREAD_MAP = new ConcurrentHashMap<>();
    @Resource
    private ChannelContextUtils channelContextUtils;
    @Resource
    private RedisComponent redisComponent;
    @Resource
    private LuoxinUtils luoxinUtils;


    @Override
    @Transactional
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) {
        Channel channel = channelHandlerContext.channel();
        String uid = channelContextUtils.getUid(channel);
        // 将消息转成dto
        ChatMessageDto chatMessageDto;
        try {
            chatMessageDto = JSON.parseObject(textWebSocketFrame.text(), ChatMessageDto.class);
            if (StrUtil.isEmpty(chatMessageDto.getMessageContent())
                    || chatMessageDto.getContactId() == null
                    || chatMessageDto.getMessageType() == null) {
                channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(AjaxResult.errorMsg_400(BaseException.PARAMS_ERROR))));
                return;
            }
        } catch (Exception ignore) {
            channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(AjaxResult.errorMsg_400(BaseException.PARAMS_ERROR))));
            return;
        }
        // 通过联系类型进行分流
        switch (chatMessageDto.getMessageType()) {
            case CHAT:
                break;
            case CHAT_V_COUNSELOR:
                if (V_COUNSELOR_ASK_CHANNEL_THREAD_MAP.containsKey(channel)) {
                    channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(AjaxResult.errorMsg(443, ChatException.CURRENT_IN_ASK))));
                    break;
                }
                Thread thread = new Thread(() -> {
                    luoxinUtils.askQuestion(chatMessageDto, uid, channel, ChatMessageTypeEnum.CHAT_V_COUNSELOR);
                    V_COUNSELOR_ASK_CHANNEL_THREAD_MAP.remove(channel);
                });
                thread.start();
                V_COUNSELOR_ASK_CHANNEL_THREAD_MAP.put(channel, thread);
                break;
            case STOP_V_COUNSELOR_ANSWER:
                // 检查该通道是否被线程占用，占用则清除占用
                if (V_COUNSELOR_ASK_CHANNEL_THREAD_MAP.containsKey(channel)) {
                    V_COUNSELOR_ASK_CHANNEL_THREAD_MAP.get(channel).interrupt();
                    V_COUNSELOR_ASK_CHANNEL_THREAD_MAP.remove(channel);
                }
                ChatCommonVo chatCommonVo = new ChatCommonVo();
                chatCommonVo.setMessageType(ChatMessageTypeEnum.STOP_V_COUNSELOR_ANSWER);
                LuoxinUtils.SendSuccessBody(chatCommonVo, channel);
                break;
            case AUDIO_CHAT_VC:
                if (V_COUNSELOR_ASK_CHANNEL_THREAD_MAP.containsKey(channel)) {
                    channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(AjaxResult.errorMsg(443, ChatException.CURRENT_IN_ASK))));
                    break;
                }
                Thread tOfAudioVc = new Thread(() -> {
                    luoxinUtils.audioChatWithVc(chatMessageDto, uid, channel);
                    V_COUNSELOR_ASK_CHANNEL_THREAD_MAP.remove(channel);
                });
                tOfAudioVc.start();
                V_COUNSELOR_ASK_CHANNEL_THREAD_MAP.put(channel, tOfAudioVc);
                break;
            case GROUP_CREATE:
                break;
            case CONTACT_APPLY:
                break;
            case ADD_FRIEND:
                break;
            case MEDIA_CHAT:
                break;
            case FILE_UPLOAD:
                break;
            case FORCE_OFF_LINE:
                break;
            case DISSOLUTION_GROUP:
                break;
            case ADD_GROUP:
                break;
            case GROUP_NAME_UPDATE:
                break;
            case KICK_OUT_GROUP:
                break;
            case REMOVE_GROUP:
                break;

        }

    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        //处理协议
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete complete) {
            // 获取token
            String token = getToken(complete.requestUri());
            if (Objects.isNull(token)) {
                sendJsonMessage(ctx.channel(), AjaxResult.errorMsg_403());
                ctx.channel().close();
                return;
            }
            // 校验token
            Integer uid = redisComponent.getUidByToken(token);
            if (Objects.isNull(uid)) {
                sendJsonMessage(ctx.channel(), AjaxResult.errorMsg_403());
                ctx.channel().close();
                return;
            }
            // 将当前通道和用户建立关系
            channelContextUtils.addUid(uid.toString(), ctx.channel());
            // 发送初始化消息
            new Thread(() -> {
                luoxinUtils.initConnection(uid.toString(), ctx.channel());
            }).start();
        }
    }

    private String getToken(String uri) {
        if (StrUtil.isBlank(uri))
            return null;
        String[] requestParams = uri.split("\\?");
        if (requestParams.length != 2)
            return null;
        String[] params = requestParams[1].split("=");
        if (params.length != 2 || !params[0].equals("token"))
            return null;
        return params[1];
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.info("有新连接加入");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info("有链接断开");
        // 将当前连接移除
        channelContextUtils.detachFromGroups(ctx.channel(), channelContextUtils.getUid(ctx.channel()));
    }

    public void sendJsonMessage(Channel channel, Object data) {
        channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(data)));
    }
}
